//
// cocos2d Hello World example
// http://www.cocos2d-iphone.org
//

// Import the interfaces
#import "HelloWorldScene.h"

enum {
	kTagMap = 1,
	kTagPlayer = 2,
};

#define DOWN_FORCE_SIZE 10.0f
#define DOWN_FORCE_SPEED 0.2f;
#define UP_FORCE_SIZE 8.0f

// HelloWorld implementation
@implementation HelloWorld

+(id) scene
{
	// 'scene' is an autorelease object.
	Scene *scene = [Scene node];
	
	// 'layer' is an autorelease object.
	HelloWorld *layer = [HelloWorld node];
	
	// add layer as a child to scene
	[scene addChild: layer];
	
	// return the scene
	return scene;
}

// on "init" you need to initialize your instance
-(id) init
{
	// always call "super" init
	// Apple recommends to re-assign "self" with the "super" return value
	if( (self=[super init] )) {
		
		moveDirection = 0;
		moveJump = FALSE;
		nextToGround = FALSE;
		downForce = 0.0f;
		leftRightForce = 0.0f;
		playerPosition = CGPointMake(240.0f, 100.0f); // init player position

		
		self.isTouchEnabled = TRUE;
		
		// create and initialize a Label
		Label* label = [Label labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:32];

		// ask director the the window size
		CGSize size = [[Director sharedDirector] winSize];
	
		// position the label on the center of the screen
		label.position =  ccp( size.width /2 , size.height/2 );
		
		// add the label as a child to this Layer
		[self addChild: label z:20];
		
		Sprite *gamepad = [Sprite spriteWithFile:@"gamepad.png"];
		gamepad.position = ccp( size.width /2 , size.height/2 );
		[self addChild:gamepad z:30];
		
		TMXTiledMap *map = [TMXTiledMap tiledMapWithTMXFile:@"brick1.tmx"];
		[self addChild:map z:10 tag:kTagMap];
		
		// player
		Sprite *player = [Sprite spriteWithFile:@"player.png"];
		player.scale = 0.5;
		player.position = playerPosition;
		[self addChild:player z:20 tag:kTagPlayer];
		
		[self schedule: @selector(playerMovementTick:)];

	}
	return self;
}

/*
- (BOOL)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
	NSLog(@"TouchesEnded");
	UITouch *touch = [touches anyObject];
	
	if( touch ) {
		
	}
	
	// we ignore the event. Other receivers will receive this event.
	return kEventIgnored;
}
*/


-(BOOL) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
	// NSLog(@"touch begin");
	UITouch *touch = [touches anyObject];
	if( touch ) {
		[self gamepadTouch:[[Director sharedDirector] convertToGL:[touch locationInView: [touch view]]]];
	}
	return YES;
}

-(BOOL) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
	// NSLog(@"touch ended");
	
	moveDirection = 0;
	
	return TRUE;
}

-(BOOL) ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
	// NSLog(@"touch cancelled");
	return TRUE;
}

-(BOOL) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
	NSLog(@"touch moved");
	
	UITouch *touch = [touches anyObject];

	if( touch ) {
		[self gamepadTouch:[[Director sharedDirector] convertToGL:[touch locationInView: [touch view]]]];
		/*
		CGPoint touchLocation = [touch locationInView: [touch view]];	
		CGPoint prevLocation = [touch previousLocationInView: [touch view]];	
		
		touchLocation = [[Director sharedDirector] convertToGL: touchLocation];
		prevLocation = [[Director sharedDirector] convertToGL: prevLocation];
		
		CGPoint diff = ccpSub(touchLocation,prevLocation);
		NSLog(@"TouccMoved diff: (%f,%f)", diff.x, diff.y);
		
		CGPoint diffMove = CGPointMake(diff.x, 0.0f);
		CocosNode *node = [self getChildByTag:kTagMap];
		CGSize mapSize = [node contentSize];
		CGSize winSize = [[Director sharedDirector] winSize];
		CGPoint currentPos = [node position];
		
		if(currentPos.x + diffMove.x > 0.0f){
			diffMove.x = 0.0f - currentPos.x;
		}
		if(currentPos.x + diffMove.x + mapSize.width < winSize.width){
			// NSLog(@"right bdr");
			diffMove.x = winSize.width - currentPos.x - mapSize.width;
		}
		
		[node setPosition: ccpAdd(currentPos, diffMove)];

		NSLog(@"mapWidth: %f, winWidth: %f, pos.x: %f, diff.x:%f", mapSize.width, winSize.width, currentPos.x, diffMove.x);
		// NSLog(@"winSize: %f", winSize.width);
		*/
	}
	
	return TRUE;
}

- (unsigned int)tileGid:(TMXLayer *)layer at:(CGPoint)point {

	// check if next to ground
	// TMXLayer *wallLayer = [map layerNamed:@"wall"];
	// NSLog(@"player at %f,%f", player.position.x, bottom);
	// AtlasSprite *tile = [wallLayer tileAt:ccp(player.position.x,bottom)];
	CGPoint tileCoord;
	tileCoord.x = floor( point.x / 24 );
	tileCoord.y = floor(( 24 * 16 - point.y ) / 24);
	// NSLog(@"bottom coord %f,%f", tileCoord.x, tileCoord.y);
	return [layer tileGIDAt:tileCoord];
}

- (CGPoint)pointToCoord:(CGPoint) point {
	CGPoint tileCoord; 
	tileCoord.x = floor( point.x / 24.0f ); 
	tileCoord.y = floor(( 24.0f * 16.0f - point.y ) / 24.0f); 
	return tileCoord;
}

- (float)tileTop:(CGPoint)point {
	CGPoint tileCoord = [self pointToCoord:point];
	// NSLog(@"%f,%f", tileCoord.x, tileCoord.y);
	return ( 16.0f - 1.0f - tileCoord.y ) * 24.0f + 24.0f;	
}

- (float)tileBottom:(CGPoint)point {
	CGPoint tileCoord = [self pointToCoord:point];
	return ( 16.0f - 1.0f - tileCoord.y ) * 24.0f;	
}

- (float)tileLeft:(CGPoint)point {
	CGPoint tileCoord = [self pointToCoord:point];
	return tileCoord.x * 24.0f;	
}

- (float)tileRight:(CGPoint)point {
	CGPoint tileCoord = [self pointToCoord:point];
	return tileCoord.x * 24.0f + 24.0f;	
}

-(void) playerMovementTick: (ccTime) dt
{
	// NSLog(@"tick");
	
    // check player ok?
	Sprite* player = (Sprite *)[self getChildByTag:kTagPlayer];
	TMXTiledMap *map = (TMXTiledMap *)[self getChildByTag:kTagMap];
	
	CGSize playerSize = CGSizeMake(22.0f, 46.0f);
	
	float left, right, top, bottom;
	
	// CGSize winSize = [[Director sharedDirector] winSize];
	float mapOffsetX = map.position.x; // - winSize.width / 2;
	float mapOffsetY = map.position.y; // - winSize.height / 2;
	
	
	// NSLog(@"%f, %f", map.position.x, map.position.y);
	
	// NSLog(@"player height %f", playerSize.height);

	
	
	// check if next to ground
	TMXLayer *wallLayer = [map layerNamed:@"wall"];
	// NSLog(@"player at %f,%f", player.position.x, bottom);
	// AtlasSprite *tile = [wallLayer tileAt:ccp(player.position.x,bottom)];
	// CGPoint tileCoord;
	// tileCoord.x = floor( player.position.x / 24 );
	// tileCoord.y = floor(( 24 * 16 - bottom ) / 24);
	// NSLog(@"bottom coord %f,%f", tileCoord.x, tileCoord.y);
	
	
	BOOL downBreak = FALSE;
	BOOL upBreak = FALSE; // head in wall
	BOOL leftBreak = FALSE;
	BOOL rightBreak = FALSE;
	
	///////////////////////////
	// COLLICSION DECTECTION //
	///////////////////////////
	
	
	
	
	left =	round(player.position.x	- playerSize.width / 2	- mapOffsetX);
	right = round(player.position.x	+ playerSize.width / 2	- mapOffsetX);
	top =	round(player.position.y	+ playerSize.height / 2 - mapOffsetY);
	bottom = round(player.position.y	- playerSize.height / 2 - mapOffsetY);
	
	unsigned int footTileGid1 = [self tileGid:wallLayer at:CGPointMake(left + 1.0f, bottom - 1.0f)];
	unsigned int footTileGid2 = [self tileGid:wallLayer at:CGPointMake(right - 1.0f, bottom - 1.0f)];
	unsigned int headTileGid1 = [self tileGid:wallLayer at:CGPointMake(left + 1.0f, top + 1.0f)];
	unsigned int headTileGid2 = [self tileGid:wallLayer at:CGPointMake(right - 1.0f, top + 1.0f)];
	
	downBreak = FALSE;
	
	if(footTileGid1 > 0 || footTileGid2 > 0){
		// wall, player on the wall
		// NSLog(@"on wall %d", tileGid);
		downBreak = TRUE;
		// NSLog(@"next to ground");
		// check INBREAK
		float wallTop = [self tileTop:CGPointMake(left, bottom - 1.0f)];
		// NSLog(@"y t %f %f", player.position.y, wallTop);
		if(bottom <= wallTop){
			NSLog(@"bottom inbreak");
			float newY = wallTop + playerSize.height / 2 + 1.0f;
			player.position = CGPointMake(player.position.x, newY);
		}
	} else if(headTileGid1 > 0 || headTileGid2 > 0){
		// wall, player head in the wall
		// NSLog(@"on wall %d", tileGid);
		upBreak = TRUE;
		
		// check INBREAK
		float wallBottom = [self tileBottom:CGPointMake(left, top + 1.0f)];
		// NSLog(@"y t %f %f", player.position.y, wallTop);
		if(top >= wallBottom){
			NSLog(@"top inbreak");
			float newY = wallBottom - playerSize.height / 2 - 1.0f;
			player.position = CGPointMake(player.position.x, newY);
		}
		
		
	}
	
	if(downBreak){
		nextToGround = TRUE;
	} else {
		nextToGround = FALSE;
	}
	
	left =	round(player.position.x	- playerSize.width / 2	- mapOffsetX);
	right = round(player.position.x	+ playerSize.width / 2	- mapOffsetX);
	top =	round(player.position.y	+ playerSize.height / 2 - mapOffsetY);
	bottom = round(player.position.y	- playerSize.height / 2 - mapOffsetY);
	
	unsigned int leftTileGid1 = [self tileGid:wallLayer at:CGPointMake(left - 1.0f, top)];
	unsigned int leftTileGid2 = [self tileGid:wallLayer at:CGPointMake(left - 1.0f, ( top + bottom) / 2)];
	unsigned int leftTileGid3 = [self tileGid:wallLayer at:CGPointMake(left - 1.0f, bottom)];
	unsigned int rightTileGid1 = [self tileGid:wallLayer at:CGPointMake(right + 1.0f, top)];
	unsigned int rightTileGid2 = [self tileGid:wallLayer at:CGPointMake(right + 1.0f, ( top + bottom) / 2)];
	unsigned int rightTileGid3 = [self tileGid:wallLayer at:CGPointMake(right + 1.0f, bottom)];
	
	
	if(leftTileGid1 > 0 || leftTileGid2 > 0 || leftTileGid3 > 0){
		// wall, player head in the wall
		// NSLog(@"on wall %d", tileGid);
		leftBreak = TRUE;
		// NSLog(@"left break");
		// check INBREAK
		float wallRight = [self tileRight:CGPointMake(left - 1.0f, bottom)];
		// NSLog(@"y t %f %f", player.position.y, wallTop);
		if(left <= wallRight){
			NSLog(@"left inbreak");
			float newX = wallRight + playerSize.width / 2 + 0.0f + mapOffsetX;
			player.position = CGPointMake(newX, player.position.y);
		}
	} else if(rightTileGid1 > 0 || rightTileGid2 > 0 || rightTileGid3 > 0){
		// wall, player head in the wall
		// NSLog(@"on wall %d", tileGid);
		rightBreak = TRUE;
		
		// check INBREAK
		float wallLeft = [self tileLeft:CGPointMake(right + 1.0f, bottom)];
		// NSLog(@"y t %f %f", player.position.y, wallTop);
		if(right >= wallLeft){
			NSLog(@"right inbreak");
			float newX = wallLeft - playerSize.width / 2 - 0.0f + mapOffsetX;
			NSLog(@"newX %f %f %f", wallLeft, mapOffsetX, newX);
			player.position = CGPointMake(newX, player.position.y);
		}
	} else {
		// player in the air.
		// go down... or continue uping
		
	}
	
	
	if(nextToGround){
		// reset downforce
		downForce = 0.0f;
		
		// can do jump
		
		// check JUMP
		if(moveJump){
			upForce = UP_FORCE_SIZE;
			NSLog(@"set upforce");
			// clear jump
			moveJump = FALSE;
			nextToGround = FALSE;
		}

	} 
	
	// sin(1.0);
	if(upBreak){
		downForce = upForce;
		upForce = 0.0f;
	}
	
	// try go down
	
	if(!nextToGround || upForce > 0.0f){
		float upPixel = 0.0f;
		float downPixel = 0.0f;
		
		if(upForce > 0.0f){
			upPixel = upForce ;
		} else {
			downPixel = downForce;
		}
		
		player.position = ccp(player.position.x, player.position.y - downPixel + upPixel);

		if(upForce > 0.0f){
			upForce = upForce - DOWN_FORCE_SPEED;
		} else if(downForce < DOWN_FORCE_SIZE){
			downForce = downForce + DOWN_FORCE_SPEED;
		} else {
			upForce = 0.0f;
			downForce = DOWN_FORCE_SIZE;
		}
		NSLog(@"up down %f %f", upForce, downForce);
	}
		
	
	
	if(leftBreak && moveDirection < 0){
		// moveDirection = 0;
		NSLog(@"left break");
	} else if(rightBreak && moveDirection > 0){
		// moveDirection = 0;
		NSLog(@"right break");
	} else if(moveDirection != 0){
		// execute go left or right
		float movement = moveDirection * leftRightForce;
		
		CGPoint move = ccp(-movement, 0.0f);
		
		// try scroll map first
		if(player.position.x < 150.0f && movement < 0.0f){
			move = [self scrollMap:move];
		}else if(player.position.x > 330.0f && movement > 0.0f){
			move = [self scrollMap:move];
		}
		
		NSLog(@"move player %f,%f", move.x, move.y);
		// them move player
		player.position = ccp(player.position.x - move.x, player.position.y - move.y);
		
		if(leftRightForce < 2.0f){
			leftRightForce = leftRightForce + 0.2f;
		}
	}
}


- (void) gamepadTouch:(CGPoint)touchPos {
	// check if touch in gamepad
	
	// NSLog(@"gamepad at: %f,%f", touchPos.x, touchPos.y);
		
	if(CGRectContainsPoint(CGRectMake(15.0f, 15.0f, 45.0f, 45.0f), touchPos)){
		moveDirection = -1;
		NSLog(@"go left");
	} else if (CGRectContainsPoint(CGRectMake(72.0f, 15.0f, 45.0f, 45.0f), touchPos)){
		moveDirection = 1;
		NSLog(@"go right");
	} else if (CGRectContainsPoint(CGRectMake(422.0f, 15.0f, 45.0f, 45.0f), touchPos)){
		if(nextToGround){
			moveJump = TRUE;
		}
		NSLog(@"go jump");
	}
}

/**
 * 
 * @return diff not handled
 */
- (CGPoint) scrollMap:(CGPoint)diff {
	
	// NSLog(@"TouccMoved diff: (%f,%f)", diff.x, diff.y);
	
	CGPoint diffMove = CGPointMake(diff.x, 0.0f);
	CocosNode *node = [self getChildByTag:kTagMap];
	CGSize mapSize = [node contentSize];
	CGSize winSize = [[Director sharedDirector] winSize];
	CGPoint currentPos = [node position];
	
	if(currentPos.x + diffMove.x > 0.0f){
		diffMove.x = 0.0f - currentPos.x;
	}
	if(currentPos.x + diffMove.x + mapSize.width < winSize.width){
		// NSLog(@"right bdr");
		diffMove.x = winSize.width - currentPos.x - mapSize.width;
	}
	
	[node setPosition: ccpAdd(currentPos, diffMove)];
	
	// NSLog(@"mapWidth: %f, winWidth: %f, pos.x: %f, diff.x:%f", mapSize.width, winSize.width, currentPos.x, diffMove.x);
	// NSLog(@"winSize: %f", winSize.width);
	
	return CGPointMake(diff.x - diffMove.x, diff.y - diffMove.y);
}


// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
	// in case you have something to dealloc, do it in this method
	// in this particular example nothing needs to be released.
	// cocos2d will automatically release all the children (Label)
	
	// don't forget to call "super dealloc"
	[super dealloc];
}
@end
